﻿#include "datasimustorage.h"
#include "datasimucache.h"
#include "globalstatic.h"

#include "sdk/QsLog/include/QsLog.h"

#include <QDebug>
#include <QDir>
#include <QDateTime>
#include <QApplication>
#include <QRandomGenerator>

DataSimuStorage::DataSimuStorage(QSettings* settings, QList<ChannelDescription> channelDescriptionList, QList<ReportLine> reportLineList, QObject *parent) : QObject(parent),
    m_settings(settings),
    m_channelDescriptionList(channelDescriptionList),
    m_reportLineList(reportLineList),
    m_opened(false)
{
    // 初始化
    init();
}

DataSimuStorage::~DataSimuStorage()
{
    // 关闭文件, 删除数据流
    if (m_dataStream != nullptr) {
        delete m_dataStream;
        m_dataStream = nullptr;
    }
    if (m_dataFile != nullptr) {
        m_dataFile->close();
        delete m_dataFile;
        m_dataFile = nullptr;
    }

    if (m_reportStream != nullptr) {
        delete m_reportStream;
        m_reportStream = nullptr;
    }
    if (m_reportFile != nullptr) {
        m_reportFile->close();
        delete m_reportFile;
        m_reportFile = nullptr;
    }
}

void DataSimuStorage::init()
{
    m_settings->beginGroup("Storage");
    QString savePath = m_settings->value("savePath").toString();
    QString reportPath = m_settings->value("reportPath").toString();
    m_settings->endGroup();

    m_savePath = savePath.prepend(qApp->applicationDirPath());
    QDir dataDir(m_savePath);
    if(!dataDir.exists()) {
        // 判断文件夹是否存在，不存在则创建
        dataDir.mkpath(m_savePath);
    }
    m_reportPath = reportPath.prepend(qApp->applicationDirPath());
    QDir reportDir(m_reportPath);
    if(!reportDir.exists()) {
        // 判断文件夹是否存在，不存在则创建
        reportDir.mkpath(m_reportPath);
    }

    // 计算字节长度: 第0个元素表示时间(8字节), 第1-96个元素表示通道值(根据数据类型计算)
    GlobalStatic::initDataType();
    int dataLength = sizeof(qint64);
    for (int i = 0; i < m_channelDescriptionList.size(); i++) {
        DataType dataType = GlobalStatic::getDataType(m_channelDescriptionList.at(i).dataType);
        switch (dataType) {
        case UC:
        case SC:
            dataLength += sizeof(char);
            break;
        case US:
        case SS:
            dataLength += sizeof(short);
            break;
        case UI:
        case SI:
            dataLength += sizeof(int);
            break;
        case UL:
        case SL:
            dataLength += sizeof(long long);
            break;
        case F32:
        case F:
            dataLength += sizeof(float);
            break;
        case F64:
        case DBL:
            dataLength += sizeof(double);
            break;
        default:
            break;
        }
    }
    GlobalStatic::setDataLength(dataLength);
    //qDebug() << "****dataLength: " << dataLength;
}

void DataSimuStorage::storageReport()
{
    if (!m_opened)
        return;

    // 测试级别
    m_settings->beginGroup("Servo");
    int level = m_settings->value("level").toInt();
    m_settings->endGroup();

    // 测试级别
    *m_reportStream << level << "\n";

    m_settings->beginGroup("SystemSet");
    int item = m_settings->value("item").toInt();
    int stage = m_settings->value("stage").toInt();
    QString A1Num = m_settings->value("A1Num").toString();
    QString A2Num = m_settings->value("A2Num").toString();
    QString A3Num = m_settings->value("A3Num").toString();
    QString A4Num = m_settings->value("A4Num").toString();
    QString CtrlNum = m_settings->value("CtrlNum").toString();
    QString tempeture = m_settings->value("tempeture").toString();
    QString humidity = m_settings->value("humidity").toString();
    QString person = m_settings->value("person").toString();
    QString kdperv = m_settings->value("kdperv").toString();
    QString description = m_settings->value("description").toString();
    QStringList servoMachineList = m_settings->value("servoMachine").toStringList();
    m_settings->endGroup();

    // 测试项目
    QString itemString;
    switch (item) {
    case 0:
        itemString = QStringLiteral("总成");
        break;
    case 1:
        itemString =  QStringLiteral("单元");
        break;
    default:
        break;
    }
    *m_reportStream << itemString << "\n";

    // 测试阶段
    QString stageString;
    switch (stage) {
    case 0:
        stageString = "M";
        break;
    case 1:
        stageString =  "C";
        break;
    case 2:
        stageString = "S";
        break;
    case 3:
        stageString = "D";
        break;
    default:
        break;
    }
    *m_reportStream << stageString << "\n";

    *m_reportStream << A1Num << "\n";
    *m_reportStream << A2Num << "\n";
    *m_reportStream << A3Num << "\n";
    *m_reportStream << A4Num << "\n";
    *m_reportStream << CtrlNum << "\n";
    *m_reportStream << tempeture << "\n";
    *m_reportStream << humidity << "\n";
    *m_reportStream << person << "\n";
    *m_reportStream << kdperv << "\n";
    *m_reportStream << description  << "\n";
    *m_reportStream << servoMachineList.join(",") << "\n";

    if (level == 1) {
        for (int i = 14; i < 88; i++) {
            double value0 = QRandomGenerator::global()->generateDouble() * (m_reportLineList.at(i).maxValue1 - m_reportLineList.at(i).minValue1) + m_reportLineList.at(i).minValue1;
            double value1 = QRandomGenerator::global()->generateDouble() * (m_reportLineList.at(i).maxValue1 - m_reportLineList.at(i).minValue1) + m_reportLineList.at(i).minValue1;
            double value2 = QRandomGenerator::global()->generateDouble() * (m_reportLineList.at(i).maxValue1 - m_reportLineList.at(i).minValue1) + m_reportLineList.at(i).minValue1;
            double value3 = QRandomGenerator::global()->generateDouble() * (m_reportLineList.at(i).maxValue1 - m_reportLineList.at(i).minValue1) + m_reportLineList.at(i).minValue1;
            *m_reportStream << QString::number(value0, 'f', 3) << "," << QString::number(value1, 'f', 3) << "," << QString::number(value2, 'f', 3) << "," << QString::number(value3, 'f', 3) << "\n";
        }
    }

    if (level == 2) {
        for (int i = 14; i < 88; i++) {
            double value0 = QRandomGenerator::global()->generateDouble() * (m_reportLineList.at(i).maxValue2 - m_reportLineList.at(i).minValue2) + m_reportLineList.at(i).minValue2;
            double value1 = QRandomGenerator::global()->generateDouble() * (m_reportLineList.at(i).maxValue2 - m_reportLineList.at(i).minValue2) + m_reportLineList.at(i).minValue2;
            double value2 = QRandomGenerator::global()->generateDouble() * (m_reportLineList.at(i).maxValue2 - m_reportLineList.at(i).minValue2) + m_reportLineList.at(i).minValue2;
            double value3 = QRandomGenerator::global()->generateDouble() * (m_reportLineList.at(i).maxValue2 - m_reportLineList.at(i).minValue2) + m_reportLineList.at(i).minValue2;
            *m_reportStream << QString::number(value0, 'f', 3) << "," << QString::number(value1, 'f', 3) << "," << QString::number(value2, 'f', 3) << "," << QString::number(value3, 'f', 3) << "\n";
        }
    }
}

void DataSimuStorage::onOpen()
{
    // 当前时间
    QString dtCurrentString = QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss");
    // 生成并打开文件: data
    m_dataFile = new QFile(QString("%1/data_%2.dat").arg(m_savePath, dtCurrentString));
    if (!m_dataFile->open(QIODevice::WriteOnly | QIODevice::Truncate)) {
        // 如果打开文件失败
        QLOG_ERROR() << "****data file of storage open faild";
        //emit sigErrorOccurred("****data file of storage open faild");
        return;
    }
    m_dataStream = new QDataStream(m_dataFile);

    // 生成并打开文件： report
    m_reportFile = new QFile(QString("%1/report_%2.csv").arg(m_reportPath, dtCurrentString));
    if (!m_reportFile->open(QIODevice::WriteOnly | QIODevice::Truncate)) {
        // 如果打开文件失败
        QLOG_ERROR() << "****report file of storage open faild";
        //emit sigErrorOccurred("****report file of storage open faild");
        return;
    }
    m_reportStream = new QTextStream(m_reportFile);

    m_settings->beginGroup("Storage");
    m_settings->setValue("lastest", dtCurrentString);
    m_settings->endGroup();

    // 标记已经创建打开了文件
    m_opened = true;
}

void DataSimuStorage::onClose()
{
    if (!m_opened)
        return;

    // 关闭文件, 删除数据流
    if (m_dataStream != nullptr) {
        delete m_dataStream;
        m_dataStream = nullptr;
    }
    if (m_dataFile != nullptr) {
        m_dataFile->close();
        delete m_dataFile;
        m_dataFile = nullptr;
    }

    // 保存报表数据
    storageReport();

    if (m_reportStream != nullptr) {
        delete m_reportStream;
        m_reportStream = nullptr;
    }
    if (m_reportFile != nullptr) {
        m_reportFile->close();
        delete m_reportFile;
        m_reportFile = nullptr;
    }

    // 标记已经关闭了文件
    m_opened = false;
}

void DataSimuStorage::onStorage(const qint64 timeStamp, const QVariantList valueList)
{
    if (!m_opened)
        return;

    // 第0个元素表示时间, 第1-96个元素表示通道值
    QByteArray buffer(sizeof(qint64), 0x0);
    memcpy(buffer.data(), &timeStamp, sizeof(qint64));

    for (int i = 0; i < valueList.size(); i++) {
        DataType dataType = GlobalStatic::getDataType(m_channelDescriptionList.at(i).dataType);
        switch (dataType) {
        case UC:
            buffer.append( static_cast<unsigned char>(valueList.at(i).toUInt() & 0xFF) );
            break;
        case SC:
            buffer.append( static_cast<unsigned char>(valueList.at(i).toInt() & 0xFF) );
            break;
        case US: {
            int value = valueList.at(i).toUInt() & 0xFFFF;
            buffer.append( static_cast<unsigned char>((value >> 8) & 0xFF) );
            buffer.append( static_cast<unsigned char>(value & 0xFF) );
        }
            break;
        case SS: {
            int value = valueList.at(i).toInt() & 0xFFFF;
            buffer.append( static_cast<unsigned char>((value >> 8) & 0xFF) );
            buffer.append( static_cast<unsigned char>(value & 0xFF) );}
            break;
        case UI: {
            int value = valueList.at(i).toUInt();
            buffer.append( static_cast<unsigned char>((value >> 24) & 0xFF) );
            buffer.append( static_cast<unsigned char>((value >> 16) & 0xFF) );
            buffer.append( static_cast<unsigned char>((value >> 8) & 0xFF) );
            buffer.append( static_cast<unsigned char>(value & 0xFF) );
        }
            break;
        case SI: {
            int value = valueList.at(i).toInt();
            buffer.append( static_cast<unsigned char>((value >> 24) & 0xFF) );
            buffer.append( static_cast<unsigned char>((value >> 16) & 0xFF) );
            buffer.append( static_cast<unsigned char>((value >> 8) & 0xFF) );
            buffer.append( static_cast<unsigned char>(value & 0xFF) );
        }
            break;
        case UL: {
            unsigned long long value = valueList.at(i).toULongLong();
            QByteArray ul(sizeof(unsigned long long), 0x0);
            memcpy(ul.data(), &value, sizeof(unsigned long long));
            buffer.append(ul);
        }
            break;
        case SL: {
            long long value = valueList.at(i).toLongLong();
            QByteArray ll(sizeof(long long), 0x0);
            memcpy(ll.data(), &value, sizeof(long long));
            buffer.append(ll);
        }
            break;
        case F32:
        case F: {
            float value = valueList.at(i).toFloat();
            QByteArray f(sizeof(float), 0x0);
            memcpy(f.data(), &value, sizeof(float));
            buffer.append(f);
        }
            break;
        case F64:
        case DBL: {
            double value = valueList.at(i).toDouble();
            QByteArray dbl(sizeof(double), 0x0);
            memcpy(dbl.data(), &value, sizeof(double));
            buffer.append(dbl);
        }
            break;
        default:
            break;
        }
    }

    // 把二进制数据写入文件, 刷新缓存
    m_dataStream->writeRawData(buffer.constData(), buffer.length());
    m_dataFile->flush();
}

